package de.fzi.kasma.learner.genetic;

import de.fzi.kasma.learner.data.Dataset;
import de.fzi.kasma.learner.function.kernel.HypothesisKernel;
import de.fzi.kasma.learner.function.prediction.EvoSVMPredictionFunction;
import de.fzi.kasma.learner.function.prediction.HypothesisPredictionFunction;
import de.fzi.kasma.learner.function.prediction.PredictionFunction;
import de.fzi.kasma.learner.function.scoring.AccuracyScoringFunction;
import de.fzi.kasma.learner.function.scoring.LossScoringFunction;
import de.fzi.kasma.learner.function.scoring.ScoringFunction;
import ec.EvolutionState;
import ec.Individual;
import ec.Population;
import ec.Problem;
import ec.coevolve.GroupedProblemForm;
import ec.simple.SimpleFitness;

public class CoevolutionProblem extends Problem implements GroupedProblemForm{

	/**
	 * 
	 */
	private static final long serialVersionUID = 700649234083499052L;


	public void preprocessPopulation(final EvolutionState state, Population pop)
	{
	           for( int i = 0 ; i < pop.subpops.length ; i++ )
	               for( int j = 0 ; j < pop.subpops[i].individuals.length ; j++ )
	                   ((SimpleFitness)(pop.subpops[i].individuals[j].fitness)).setFitness( state, 0, false );

	}

	public void postprocessPopulation(final EvolutionState state, Population pop)
	{
		for( int i = 0 ; i < pop.subpops.length ; i++ )
			for( int j = 0 ; j < pop.subpops[i].individuals.length ; j++ )
				pop.subpops[i].individuals[j].evaluated = true;
	}

	public void evaluate(final EvolutionState state,
			final Individual[] ind,  // the individuals to evaluate together
			final boolean[] updateFitness,  // should this individuals' fitness be updated?
					final boolean countVictoriesOnly, // can be neglected in cooperative coevolution
					int[] subpops,
					final int threadnum)
	{
		if( ind.length != 2 ||
				( ! ( ind[0] instanceof RLIndividual ) ) ||
				( ! ( ind[1] instanceof SLIndividual ) ) )
		{
			state.output.error( "There should be two subpopulations, one with RLIndividuals the other with SLIndividuals." );
		}

		RLIndividual ind1 = (RLIndividual)(ind[0]);
		SLIndividual ind2 = (SLIndividual)(ind[1]);

        double score = 0;
        
        Dataset dataset=((RLInitializer)state.initializer).getDataset();
        
        // where a convolution kernel is constructed based on the clauses
        // TODO: optimize the kernel calculation using graph index
        HypothesisKernel hk = new HypothesisKernel(ind1.clauses);
        double[] cfs = ind2.coeffs;
        PredictionFunction hf = null;
		try {
			hf = new EvoSVMPredictionFunction(dataset, hk, cfs);
		} catch (Exception e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}
        // Loss fcn calculates the fitness by using prediction fcn and dataset.
        ScoringFunction lsf = new AccuracyScoringFunction(hf, dataset);
        try {
			score = lsf.getScore();
			System.out.println("score "+score);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
        //TODO call prediction and scoring function here

		if( updateFitness[0] )
		{
			if( score > ind1.fitness.fitness() )
				((SimpleFitness)(ind1.fitness)).setFitness( state, (float)score, false );
		}
		if( updateFitness[1] )
		{
			if( score > ind2.fitness.fitness() )
				((SimpleFitness)(ind2.fitness)).setFitness( state, (float)score, false );
		}
	}

}

